//
//  ZHHttpDownloadService.m
//  Pod
//
//  Created by chun.chen on 2018/7/17.
//  Copyright © 2018年 cc. All rights reserved.
//

#import "ZHHttpDownloadService.h"
#import "AFNetworking.h"
#import <BCFoundation/BCFoundationUtils.h>
#import <MobileCoreServices/MobileCoreServices.h>


#define kZHHttpDownload_MaxCacheAge    60 * 60 * 24 * 7 * 2 //文件过期时间 默认2周

@interface ZHHttpDownloadService ()

@property (nonatomic, strong, nonnull) NSString *fileCachePath;
@property (nonatomic, strong, nullable) dispatch_queue_t serviceQueue;

@end

@implementation ZHHttpDownloadService

#pragma mark - system
static ZHHttpDownloadService *khttpDownloadInstance;
+ (nonnull instancetype)service {
    static dispatch_once_t httpDownloadOnceToken;
    dispatch_once(&httpDownloadOnceToken, ^{
        khttpDownloadInstance = [[ZHHttpDownloadService alloc] init];
    });
    return khttpDownloadInstance;
}
+ (instancetype)sharedInstance {
    return [ZHHttpDownloadService service];
}
- (instancetype)init {
    self = [super init];
    if (self) {
        _fileCachePath = [ZHHttpDownloadService downloadFileFolder];
        _serviceQueue = dispatch_queue_create("com.huihui.downloadQueue", DISPATCH_QUEUE_SERIAL);
        // 监听应用kill的时候删除过期文件
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillTerminateHandle) name:UIApplicationWillTerminateNotification object:nil];
    }
    return self;
}


#pragma mark - 下载文件
- (NSURLSessionDownloadTask *)downloadFileWithURL:(NSString *)url withExtension:(NSString *)fileExtension withDownloadPath:(NSString *)tempDownloadPath withProgress:(void (^)(long long, long long))progressBlock withCompletion:(void (^)(NSURL *, NSError *))completionBlock {
    if (url.length<=0) {
        if (completionBlock) {
            completionBlock(nil, [NSError errorWithDomain:NSURLErrorDomain code:-1000 userInfo:nil]);
        }
        return nil;
    }
    NSString *fileNameStr = [url lastPathComponent];
    NSString *filePathTmp = [[self class] zh_fileExistsWithName:fileNameStr withExtension:fileExtension withPath:self.fileCachePath];
    if (filePathTmp.length>0) {
        if (completionBlock) {
            completionBlock([NSURL fileURLWithPath:filePathTmp], nil);
        }
        return nil;
    }
    //目标路径
    // 返回文件存储路径
    NSString *downloadPath = [self.fileCachePath stringByAppendingPathComponent:fileNameStr];
    if (fileNameStr.pathExtension.length<=0 && fileExtension.length>0) {
        //文件URL中没有扩展名，且外面指定了扩展名
        downloadPath = [downloadPath stringByAppendingFormat:@".%@", fileExtension];
    }
    
    // 如果外界传入的有本地保存的目标路径，直接使用外部传入
    if (tempDownloadPath != nil && tempDownloadPath.length > 0) {
        downloadPath = tempDownloadPath;
    }
    //开始下载
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
    NSURL *dowmURL = [NSURL URLWithString:url];
    NSURLRequest *request = [NSURLRequest requestWithURL:dowmURL];
    NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
        if (progressBlock) {
            progressBlock(downloadProgress.totalUnitCount, downloadProgress.completedUnitCount);
        }
    } destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
        return [NSURL fileURLWithPath:downloadPath];
    } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
        if (completionBlock) {
            if (filePath == nil) {
                filePath = [NSURL fileURLWithPath:@""];
            }
            completionBlock(filePath, error);
        }
        if (error) {
            //下载失败，删除文件
            if ([[NSFileManager defaultManager] fileExistsAtPath:downloadPath]) {
                [[NSFileManager defaultManager] removeItemAtPath:downloadPath error:nil];
            }
        }
    }];
    [downloadTask resume];
    return downloadTask;
}

- (NSString *)localPathFromUrl:(NSString *)url withExtension:(NSString *)fileExtension {
    NSString *fileNameStr = [url lastPathComponent];
    NSString *filePath = [[self class] zh_fileExistsWithName:fileNameStr withExtension:fileExtension withPath:self.fileCachePath];
    return filePath;
}

#pragma mark - notifcation

/**
 删除过期文件
 */
- (void)onAppWillTerminateHandle {
    dispatch_async(self.serviceQueue, ^{
        NSFileManager*fileManager = [NSFileManager defaultManager];
        NSURL *diskCacheURL = [NSURL fileURLWithPath:self.fileCachePath isDirectory:YES];
        NSArray<NSString *> *resourceKeys = @[NSURLIsDirectoryKey, NSURLContentModificationDateKey, NSURLTotalFileAllocatedSizeKey];
        
        // This enumerator prefetches useful properties for our cache files.
        NSDirectoryEnumerator *fileEnumerator = [fileManager enumeratorAtURL:diskCacheURL includingPropertiesForKeys:resourceKeys options:NSDirectoryEnumerationSkipsHiddenFiles errorHandler:NULL];
        
        NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-kZHHttpDownload_MaxCacheAge];
        NSMutableDictionary<NSURL *, NSDictionary<NSString *, id> *> *cacheFiles = [NSMutableDictionary dictionary];
        
        // 遍历文件夹删除过期的文件
        NSMutableArray<NSURL *> *urlsToDelete = [[NSMutableArray alloc] init];
        for (NSURL *fileURL in fileEnumerator) {
            NSError *error;
            NSDictionary<NSString *, id> *resourceValues = [fileURL resourceValuesForKeys:resourceKeys error:&error];
            
            // 跳过目录&error
            if (error || !resourceValues || [resourceValues[NSURLIsDirectoryKey] boolValue]) {
                continue;
            }
            // 根据时间移除文件;
            NSDate *modificationDate = resourceValues[NSURLContentModificationDateKey];
            if ([[modificationDate laterDate:expirationDate] isEqualToDate:expirationDate]) {
                [urlsToDelete addObject:fileURL];
                continue;
            }
            cacheFiles[fileURL] = resourceValues;
        }
        for (NSURL *fileURL in urlsToDelete) {
            [fileManager removeItemAtURL:fileURL error:nil];
        }
    });
}

#pragma mark - helper
- (NSUInteger)getCacheSize {
    __block NSUInteger size = 0;
    dispatch_sync(_serviceQueue, ^{
        NSDirectoryEnumerator *fileEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:self.fileCachePath];
        for (NSString *fileName in fileEnumerator) {
            NSString *filePath = [self.fileCachePath stringByAppendingPathComponent:fileName];
            NSDictionary<NSString *, id> *attrs = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
            size += [attrs fileSize];
        }
    });
    return size;
}

- (void)clearCache {
    dispatch_async(self.serviceQueue, ^{
        [[NSFileManager defaultManager] removeItemAtPath:self.fileCachePath error:nil];
        [[NSFileManager defaultManager] createDirectoryAtPath:self.fileCachePath withIntermediateDirectories:YES attributes:nil error:nil];
    });
}


/**
 下载的文件存储目录
 
 @return return value description
 */
+ (NSString *)downloadFileFolder
{
    NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    NSString *direc = [docDir stringByAppendingPathComponent:@"com.zhihan.downloadfile"];
    if (![[NSFileManager defaultManager] fileExistsAtPath:direc]) {
        [[NSFileManager defaultManager] createDirectoryAtPath:direc withIntermediateDirectories:YES attributes:nil error:nil];
    }
    return direc;
}


/**
 通过图片Data数据第一个字节 来获取图片扩展名

 @param data data description
 @return return value description
 */
+ (NSString *)zh_getContentType:(NSData *)data {
    uint8_t c;
    [data getBytes:&c length:1];
    switch (c) {
        case 0xFF:
            return @".jpeg";
        case 0x89:
            return @".png";
        case 0x47:
            return @".gif";
        case 0x49:
        case 0x4D:
            return @".tiff";
        case 0x25:
            return @".pdf";
        case 0xD0:
            return @".vnd";
        case 0x46:
            return @".txt";
        case 0x52:
            if ([data length] < 12) {
                return nil;
            }
            NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
            if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {
                return @".webp";
            }
            return nil;
    }
    return nil;
}

/**
 判断某个目录中是否存在某个文件

 @param fileName 需要查找的文件名
 @param fileExtension 指定的文件扩展名
 @param path 要搜索的目录
 @return return value description
 */
+ (NSString *) zh_fileExistsWithName:(NSString *)fileName withExtension:(NSString *)fileExtension withPath:(NSString *)path {
    NSString *filePathTmp = [path stringByAppendingPathComponent:fileName];
    NSString *fileExtensionTmp = [fileName pathExtension];
    NSString *filePathResult = nil;
    if (fileExtensionTmp.length>0) {
        //文件名中包含扩展名
        if ([[NSFileManager defaultManager] fileExistsAtPath:filePathTmp]) {
            //找到同名文件，直接返回
            filePathResult = filePathTmp;
        }
    } else {
        //文件名中没有扩展名
        NSString *fileNewPath = filePathTmp;
        if (fileExtension.length>0) {
            //如果指定了扩展名，拼接扩展名
            fileNewPath = [filePathTmp stringByAppendingFormat:@".%@", fileExtension];
        }
        if ([[NSFileManager defaultManager] fileExistsAtPath:fileNewPath]) {
            filePathResult = fileNewPath;
        }
    }
    return filePathResult;
}
@end

